package org.slf4jx.core;

import com.google.auto.service.AutoService;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileObject;
import java.net.URI;
import java.util.Set;

/**
 * 编译连接接口
 */
@AutoService(Processor.class)
@SupportedAnnotationTypes("org.slf4jx.core.EnableSlf4jx")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class Slf4jxLogProcesser extends AbstractProcessor {
    Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        filer = processingEnv.getFiler();
        super.init(processingEnv);
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        System.out.println("------------process start");
        Set<? extends Element> elementSet = roundEnv.getElementsAnnotatedWith(EnableSlf4jx.class);
        if(elementSet!=null && elementSet.size() >0){
            // 若发现有使用@EnableSlf4jx 则生成 修改的 LogFactory.class
            System.out.println("find @EnableSlf4jx class:"+elementSet);
            generateFile();
        }
        System.out.println("------------process end");
        return false;
    }

    /** 生成并写入class */
    void generateFile(){
        try {
            JavaFileObject classFile = filer.createClassFile("org.slf4j.LoggerFactory");
            URI uri= classFile.toUri();
            //尝试拿到编译项目的class 目录位置
            String dir = uri.getPath().replace("/org/slf4j/LoggerFactory.class","");
            System.out.println("class out dir："+dir);
            createClass(dir);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Could not write class:" + e);
        }
    }
    /**
     * 传入dirpath，用javassit修改后，把class 写入这个目录
     * 在 LoggerFactory.getLogger的函数里，插入下列代码，用于代理包装logger
     */
    public void createClass(String dirpath) throws Exception {
        String code =
                " if(true){\n" +
                "            java.util.function.Function function = new org.slf4jx.core.Slf4jxGetLoggerFunction();\n" +
                "            org.slf4j.Logger loggerWrap = org.slf4jx.core.Slf4jxStaticContext.loggerMap.computeIfAbsent(name, function);\n" +
                "            return loggerWrap;\n" +
                "        };";
        Class<?> lfClass = Class.forName("org.slf4j.LoggerFactory");
        javassist.ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(lfClass));
        CtClass ba = pool.get("org.slf4j.LoggerFactory");

        CtMethod ba_b = ba.getMethod("getLogger","(Ljava/lang/String;)Lorg/slf4j/Logger;");
        ba_b.insertBefore(code);
        ba.writeFile(dirpath);
    }

}
